#ifndef AUX_SOCKET_H
#define AUX_SOCKET_H
#ifdef __cplusplus
extern "C" {
#endif
#include "config.h"

#ifdef PLATFORM_WIN
#include <stdio.h>


#include <Winsock2.h>

#include <windows.h>

#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif

#define IP_STR_LENGTH_MAX   50

typedef enum
{
    SOCKET_TYPE_INVALID = -1,
    SOCKET_TYPE_UNKNOWN = 0,
    SOCKET_TYPE_CLIENT  = 1,
    SOCKET_TYPE_SERVER  = 2,

    SOCKET_TYPE_REMOTE_CLIENT = 3,

    SOCKET_MAX
} ExIPCSocketType;

typedef enum
{
    SOCKET_STATE_INVALID = -1,
    SOCKET_STATE_UNINITIALIZED = 0,
    SOCKET_STATE_INITIALIZED,
    SOCKET_STATE_INITIALIZE_FAIL,
    SOCKET_STATE_CREATED,
    SOCKET_STATE_CREATE_FAIL,
    SOCKET_STATE_CLIENT_CONNECT,   //5
    SOCKET_STATE_CLIENT_CONNECT_FAIL,
    SOCKET_STATE_SERVER_BIND,
    SOCKET_STATE_SERVER_BIND_FAIL,
    SOCKET_STATE_SERVER_LISTEN,
    SOCKET_STATE_SERVER_LISTEN_FAIL, //10
    SOCKET_STATE_SERVER_ACCEPT,
    SOCKET_STATE_SERVER_ACCEPT_FAIL,
    SOCKET_STATE_SEND,
    SOCKET_STATE_SEND_FAIL,
    SOCKET_STATE_RECV,   //15
    SOCKET_STATE_RECV_FAIL,
    SOCKET_STATE_CLOSE,
    SOCKET_STATE_CLOSE_FAIL,
    SOCKET_STATE_DEINITIALIZED,
    SOCKET_STATE_DEINITIALIZE_FAIL, //20

    //SOCKET_STATE_REMOTE_CONNECT,
    //SOCKET_STATE_REMOTE_CLOSED,

    SOCKET_STATE_MAX
} ExIPCSocketState;

typedef enum
{
    SOCKET_ACTION_INIT,
    SOCKET_ACTION_CREAT,
    SOCKET_ACTION_CLIENT_CONNECT,
    SOCKET_ACTION_SERVER_BIND,
    SOCKET_ACTION_SERVER_LISTEN,
    SOCKET_ACTION_SERVER_ACCEPT,
    SOCKET_ACTION_SEND,
    SOCKET_ACTION_RECV,
    SOCKET_ACTION_CLOSE,
    SOCKET_ACTION_DEINIT,

    SOCKET_ACTION_MAX
} ExIPCSocketAction;

typedef enum
{
    SOCKET_STATE_INDEX_PREV_2 = 0,
    SOCKET_STATE_INDEX_PREV_1,
    SOCKET_STATE_INDEX_CUR,

    SOCKET_STATE_INDEX_MAX
} ExIPCSocketStateIndex;

typedef struct
{
#ifdef PLATFORM_WIN
    SOCKET              nSocket;
#else
    int                 nSocket;
#endif

    char                szIpStr[IP_STR_LENGTH_MAX]; /* in case ipv6 */

    u16                 wPort;
    ExIPCSocketState    eSocketStat[SOCKET_STATE_INDEX_MAX];
    ExIPCSocketType     eType;
} TxIPCSocket;



typedef struct {
    EErrNo (*PlatformInit)();
    EErrNo (*Init)(TxIPCSocket *ptSocket);
    EErrNo (*Create)(TxIPCSocket *ptSocket, s32 nSendTimeout, s32 nRecvTimeout);
    EErrNo (*Connect)(TxIPCSocket *ptSocket);
    EErrNo (*Send)(TxIPCSocket *ptSocket, u8 *pabyData, s32 *pnSize);
    EErrNo (*Recv)(TxIPCSocket *ptSocket, u8 *pabyData, s32 *pnSize);
    EErrNo (*Close)(TxIPCSocket *ptSocket);
    EErrNo (*Deinit)(TxIPCSocket *ptSocket);
    EErrNo (*Bind)(TxIPCSocket *ptSocket);
    EErrNo (*Listen)(TxIPCSocket *ptSocket);
    EErrNo (*Accept)(TxIPCSocket *ptLocal, TxIPCSocket *ptRemote);
    EErrNo (*Reset)(TxIPCSocket *ptSocket);
    EErrNo (*Shutdown)(TxIPCSocket *ptSocket, u8 byRx, u8 byTx);
    EErrNo (*PlatformDeinit)();
    EErrNo eLoad;
} TxIPCSocketInterface;

typedef struct {
    EErrNo (*Start)(TxIPCSocket* ptSocket, char *pszIp, u16 wPort, s32 nSendTimeout,
                                                              s32 nRecvTimeout);
    EErrNo (*WaitClient)(TxIPCSocket* ptLocal, TxIPCSocket *ptRemote);
    EErrNo (*Send)(TxIPCSocket* ptLocal, TxIPCSocket *ptRemote,
                   u8 *pabyData, s32 *pnSize);
    EErrNo (*Recv)(TxIPCSocket* ptLocal, TxIPCSocket *ptRemote,
                                    u8 *pabyData, s32 *pnSize);
    EErrNo (*CloseClient)(TxIPCSocket* ptLocal, TxIPCSocket *ptRemote);
    EErrNo (*Exit)(TxIPCSocket* ptLocal);
} TxIPCSocketServer;

typedef struct {
    EErrNo (*Start)(TxIPCSocket* pSocket, const char *pszServerIp, u16 wPort,
                    s32 nSendTimeout, s32 nRecvTimeout);
    EErrNo (*Send)(TxIPCSocket *pSocket, u8 *pabyData, s32 *pnSize);
    EErrNo (*Recv)(TxIPCSocket *pSocket, u8 *pabyData, s32 *pnSize);
    EErrNo (*Exit)(TxIPCSocket* pSocket);
} TxIPCSocketClient;


ExIPCSocketState xIPCGetSocketState(TxIPCSocket *, ExIPCSocketStateIndex);

EErrNo xIPCSetSocketState(TxIPCSocket *pSocket, ExIPCSocketStateIndex nIndex,
                        ExIPCSocketState eState);
EErrNo xIPCPushSocketState(TxIPCSocket *pSocket, ExIPCSocketState eState);
EErrNo xIPCCommonChkSocketAction(TxIPCSocket *, ExIPCSocketAction);
EErrNo xIPCPopSocketState(TxIPCSocket *pSocket, ExIPCSocketState *eState);
EErrNo xIPCGetSocketInterface(TxIPCSocketInterface *ptInterface);

#define xIPCChkCurSocketState(ptSocket, eState) \
    (eState == xIPCGetSocketState(ptSocket, SOCKET_STATE_INDEX_CUR))

#define xIPCChkCurSocketUninitialized(ptSocket) \
    xIPCChkCurSocketState(ptSocket, SOCKET_STATE_UNINITIALIZED)

#define xIPCPushCurSocketState(ptSocket, eState) \
    (xIPCPushSocketState(ptSocket, eState))

#ifdef PLATFORM_WIN
#define LOCAL_IP_STR  "127.0.0.1"
#else
#define LOCAL_IP_STR  "127.0.0.1"
#endif

EErrNo xIPCComponentSocketInit();
EErrNo xIPCComponentSocketDeinit();

EErrNo xIPCComponentGetSocketClientInterface(TxIPCSocketClient *);
EErrNo xIPCComponentPutSocketClientInterface(TxIPCSocketClient *);
EErrNo xIPCComponentGetSocketServerInterface(TxIPCSocketServer *);
EErrNo xIPCInitSocket(TxIPCSocket *ptSocket,
                            s32 nSendTimeout, s32 nRecvTimeout);
EErrNo xIPCDeinitSocket(TxIPCSocket* pSocket);
EErrNo xIPCComponentPutSocketServerInterface(TxIPCSocketServer *pServer);

#ifdef __cplusplus
}
#endif

#endif
